import sys,time,base64,hmac,hashlib,struct

from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QProgressBar, QMessageBox,QFileDialog

from datetime import datetime

import json

from pyzbar.pyzbar import decode

from PIL import Image

from urllib.parse import unquote

from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder

import cv2
import os

import concurrent.futures

import pyotp




OTP_TYPE_UNSPECIFIED = 0
OTP_TYPE_HOTP = 1
OTP_TYPE_TOTP = 2

ALGORITHM_UNSPECIFIED = 0
ALGORITHM_SHA1 = 1
ALGORITHM_SHA256 = 2
ALGORITHM_SHA512 = 3
ALGORITHM_MD5 = 4

DIGIT_COUNT_UNSPECIFIED = 0
DIGIT_COUNT_SIX = 1
DIGIT_COUNT_EIGHT = 2

OTP_TYPE = {
    OTP_TYPE_UNSPECIFIED: 'totp',
    OTP_TYPE_HOTP: 'hotp',
    OTP_TYPE_TOTP: 'totp'
}

OTP_ALGORITHM = {
    ALGORITHM_UNSPECIFIED: 'SHA1',
    ALGORITHM_SHA1: 'SHA1',
    ALGORITHM_SHA256: 'SHA256',
    ALGORITHM_SHA512: 'SHA512',
    ALGORITHM_MD5: 'MD5'
}

OTP_DIGIT = {
    DIGIT_COUNT_UNSPECIFIED: 6,
    DIGIT_COUNT_SIX: 6,
    DIGIT_COUNT_EIGHT: 8
}




# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()

DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17otpauth-migration.proto\x12\x11otpauth_migration\"\xd1\x05\n\x07Payload\x12@\n\x0eotp_parameters\x18\x01 \x03(\x0b\x32(.otpauth_migration.Payload.OtpParameters\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x12\n\nbatch_size\x18\x03 \x01(\x05\x12\x13\n\x0b\x62\x61tch_index\x18\x04 \x01(\x05\x12\x10\n\x08\x62\x61tch_id\x18\x05 \x01(\x05\x1a\xb7\x04\n\rOtpParameters\x12\x0e\n\x06secret\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06issuer\x18\x03 \x01(\t\x12\x45\n\talgorithm\x18\x04 \x01(\x0e\x32\x32.otpauth_migration.Payload.OtpParameters.Algorithm\x12\x43\n\x06\x64igits\x18\x05 \x01(\x0e\x32\x33.otpauth_migration.Payload.OtpParameters.DigitCount\x12>\n\x04type\x18\x06 \x01(\x0e\x32\x30.otpauth_migration.Payload.OtpParameters.OtpType\x12\x0f\n\x07\x63ounter\x18\x07 \x01(\x04\"y\n\tAlgorithm\x12\x19\n\x15\x41LGORITHM_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x41LGORITHM_SHA1\x10\x01\x12\x14\n\x10\x41LGORITHM_SHA256\x10\x02\x12\x14\n\x10\x41LGORITHM_SHA512\x10\x03\x12\x11\n\rALGORITHM_MD5\x10\x04\"U\n\nDigitCount\x12\x1b\n\x17\x44IGIT_COUNT_UNSPECIFIED\x10\x00\x12\x13\n\x0f\x44IGIT_COUNT_SIX\x10\x01\x12\x15\n\x11\x44IGIT_COUNT_EIGHT\x10\x02\"I\n\x07OtpType\x12\x18\n\x14OTP_TYPE_UNSPECIFIED\x10\x00\x12\x11\n\rOTP_TYPE_HOTP\x10\x01\x12\x11\n\rOTP_TYPE_TOTP\x10\x02\x62\x06proto3')

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'otpauth_migration_pb2', _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
  DESCRIPTOR._options = None
  _globals['_PAYLOAD']._serialized_start=47
  _globals['_PAYLOAD']._serialized_end=768
  _globals['_PAYLOAD_OTPPARAMETERS']._serialized_start=201
  _globals['_PAYLOAD_OTPPARAMETERS']._serialized_end=768
  _globals['_PAYLOAD_OTPPARAMETERS_ALGORITHM']._serialized_start=485
  _globals['_PAYLOAD_OTPPARAMETERS_ALGORITHM']._serialized_end=606
  _globals['_PAYLOAD_OTPPARAMETERS_DIGITCOUNT']._serialized_start=608
  _globals['_PAYLOAD_OTPPARAMETERS_DIGITCOUNT']._serialized_end=693
  _globals['_PAYLOAD_OTPPARAMETERS_OTPTYPE']._serialized_start=695
  _globals['_PAYLOAD_OTPPARAMETERS_OTPTYPE']._serialized_end=768



class Converter(object):

    def __init__(self):
        self.payload = Payload()

    def to_plain(self):
        pass

    def from_migration_string(self, migration_string):

        data = unquote(migration_string.split('data=')[1])

        self.payload.ParseFromString(base64.b64decode(data))

    def to_plain_string(self):

        otp_str_list = []
        for otp_item in self.payload.otp_parameters:

            otp_type = OTP_TYPE[otp_item.type]
            issuer = otp_item.issuer
            name = otp_item.name
            label = f'{issuer}:{name}'
            secret = base64.b32encode(otp_item.secret).decode()
            otp_algorithm = OTP_ALGORITHM[otp_item.algorithm]
            digits = OTP_DIGIT[otp_item.digits]
            counter = otp_item.counter

            otp_url = f'otpauth://{otp_type}/{label}?secret={secret}&issuer={otp_item.issuer}&algorithm={otp_algorithm}&digits={digits}'
            if otp_type == OTP_TYPE_HOTP:
                otp_url += f'&counter={counter}'

            print(otp_url)
            otp_str_list.append(otp_url)
        return otp_str_list

        # print(otp_str_list)



class MyQrcode:
    def __init__(self):
        pass

    def main(self, file_paths):

        if not self.check_file_path(file_paths):
            print('File not found.')
            sys.exit(-1)

        migration_list = self.get_str_from_qr_code(file_paths)
        plain_list = self.convert(migration_list)
        for each_plain in plain_list:
            print(each_plain)

    def getPlainPath(self, file_path):
        if not self.check_file_path([file_path]):
            print('File not found.')
            sys.exit(-1)

        migration_list = self.get_str_from_qr_code([file_path])
        if (migration_list[0].startswith("otpauth:")):
           plain_list = migration_list
        else:
            try:
                plain_list = self.convert(migration_list)
            except Exception as e:
                accountList = eval(migration_list[0])
                plain_list = ['otpauth://totp/sangfor:{}?secret={}'.format(accountList[0]["account"],accountList[0]["secret"])]


        return plain_list[0]

    def filter_alnum(self, s):
        result = ''.join(ch for ch in s if ch.isalpha() and ch.isascii() or ch.isdigit())
        return result

    def getSecretAndAccount(self, file_path):
        plainPath = self.getPlainPath(file_path)
        print(plainPath)
        s1 = plainPath.split("?")
        account = s1[0].split(":")[-1].replace("//totp/","")
        secret = self.filter_alnum(s1[1].split("&")[0].split("=",1)[-1])
        return account, secret

    def convert(self, migration_list):
        plain_list = []
        for migration in migration_list:
            converter = Converter()
            converter.from_migration_string(migration)
            each_plain_list = converter.to_plain_string()
            plain_list.extend(each_plain_list)

        return plain_list


    def get_str_from_qr_code(self, file_paths):

        migration_list = []
        for each_file_path in file_paths:
            migration_str = self.read_qr_code(each_file_path)
            migration_list.append(migration_str)

        return migration_list


    def read_qr_code(self, file_path):
        qr_file = cv2.imread(file_path)
        qr_detector = cv2.QRCodeDetector()
        result = qr_detector.detectAndDecode(qr_file)

        return result[0]


    def check_file_path(self, file_path):
        for each_file_path in file_path:
            if not os.path.isfile(each_file_path):
                print(f'File not found: {each_file_path}')
                return False

        return True



def calGoogleCode(secretKey):
    if (len(secretKey) == 52):
        # 创建一个TOTP对象
        totp = pyotp.TOTP(secretKey)
        # 获取当前的时间一次性密码
        googleCode = totp.now()
    else:
        input = int(time.time()) // 30
        key = base64.b32decode(secretKey)
        msg = struct.pack(">Q", input)
        googleCode = hmac.new(key, msg, hashlib.sha1).digest()
        #版本判断
        if (sys.version_info> (2, 7)):
            o = googleCode[19] & 15
        else:
            o = ord(googleCode[19]) & 15
        googleCode = str((struct.unpack(">I", googleCode[o:o + 4])[0] & 0x7fffffff) % 1000000)
        # if len(googleCode) == 5:
        #     googleCode = '0' + googleCode
        # 如果验证码的第一位是0，则不会显示。此处判断若是5位码，则在第一位补上0
        googleCode = googleCode.zfill(6)
    return googleCode





class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("google auth")
        Dialog.resize(800, 600)

        self.secret_input = QtWidgets.QLineEdit(Dialog)
        self.secret_input.setGeometry(QtCore.QRect(360, 519, 211, 40))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(14)
        self.secret_input.setFont(font)
        self.secret_input.setObjectName("secret_input")
        self.secret_label = QtWidgets.QLabel(Dialog)
        self.secret_label.setGeometry(QtCore.QRect(280, 520, 60, 30))
        self.secret_label.setMinimumSize(QtCore.QSize(60, 30))
        self.secret_label.setMaximumSize(QtCore.QSize(60, 30))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        self.secret_label.setFont(font)
        self.secret_label.setObjectName("secret_label")
        self.addbutton = QtWidgets.QPushButton(Dialog)
        self.addbutton.setGeometry(QtCore.QRect(590, 510, 80, 60))
        self.addbutton.setMinimumSize(QtCore.QSize(80, 60))
        self.addbutton.setMaximumSize(QtCore.QSize(80, 60))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        self.addbutton.setFont(font)
        self.addbutton.setObjectName("addbutton")

        self.importbutton = QtWidgets.QPushButton(Dialog)
        self.importbutton.setGeometry(QtCore.QRect(680, 510, 80, 60))
        self.importbutton.setMinimumSize(QtCore.QSize(80, 60))
        self.importbutton.setMaximumSize(QtCore.QSize(80, 60))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        self.importbutton.setFont(font)
        self.importbutton.setObjectName("importbutton")

        self.account_label = QtWidgets.QLabel(Dialog)
        self.account_label.setGeometry(QtCore.QRect(40, 520, 60, 30))
        self.account_label.setMinimumSize(QtCore.QSize(60, 30))
        self.account_label.setMaximumSize(QtCore.QSize(60, 30))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        self.account_label.setFont(font)
        self.account_label.setObjectName("account_label")

        self.account_input = QtWidgets.QLineEdit(Dialog)
        self.account_input.setGeometry(QtCore.QRect(100, 520, 180, 40))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(14)
        self.account_input.setFont(font)
        self.account_input.setObjectName("account_input")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "google auth"))
        self.secret_label.setText(_translate("Dialog", " 秘 钥"))
        self.addbutton.setText(_translate("Dialog", "新增"))
        self.importbutton.setText(_translate("Dialog", "扫码"))
        self.account_label.setText(_translate("Dialog", "账 号"))


class MyMainForm(QMainWindow, Ui_Dialog):
    def __init__(self, parent=None):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.scheduleTask)
        self.timer.start(1000)  # 每1000毫秒（1秒）执行一次
        self.addbutton.clicked.connect(self.addConfig)
        self.importbutton.clicked.connect(self.importQrCode)
        self.currentSize = 0 # 已配置了几个
        self.configFile = {}
        self.progress_bar = QProgressBar(self)
        self.myqrcode = MyQrcode()

        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)

        self.initConfig()
        self.refreshContent()

    # 定时任务
    def scheduleTask(self):
        seconds = datetime.now().second
        if self.progress_bar.value() > 0:
            self.progress_bar.setValue(self.progress_bar.value() - 3.333)

        if (seconds % 30 == 0):
            self.refreshContent()
            self.progress_bar.setValue(100)

    # 刷新code内容
    def refreshContent(self):
        # 读取json文件获取 已配置的信息
        for i in range(len(self.configFile["data"])):
            code = calGoogleCode(self.configFile["data"][i]["secret"])

            getattr(self, "code_out" + "@" + str(i)).setText(code)
            getattr(self, "account_out" + "@" + str(i)).setText(self.configFile["data"][i]["account"])

    # 新增配置
    def addConfig(self):
        try:
            if (self.account_input.text() == "" or (len(self.secret_input.text()) != 16 and len(self.secret_input.text()) != 52)):
                QMessageBox.information(None, '提示', '账号不能为空，且秘钥长度必须为16或52位', QMessageBox.Ok)
                return
            calGoogleCode(self.secret_input.text())
            newConfig = {"account":self.account_input.text(),"secret": self.secret_input.text()}
            self.configFile["data"].append(newConfig)

            # 写入到文件
            with open("data.json", "w") as json_file:
                json.dump(self.configFile, json_file)

            self.addSingleForm(len(self.configFile["data"]) - 1)
            self.refreshContent()
            self.account_input.setText("")
            self.secret_input.setText("")
        except Exception as e:
            print(e)


    # 初始化配置
    def initConfig(self):
        self.progress_bar.setGeometry(30, 8, 560,15)
        self.progress_bar.setValue((30 - datetime.now().second % 30)/0.3)

        try:
            with open('data.json', 'r') as file:
                self.configFile = json.load(file)
        except Exception as e:
            self.configFile = {"account_out_hight": 60, "account_out_width": 300, "code_out_hight": 60, "code_out_width": 200,"data":[]}
            # 写入到文件
            with open("data.json", "w") as json_file:
                json.dump(self.configFile, json_file)



        for i in range(len(self.configFile["data"])):
            self.addSingleForm(i)

    # 动态添加表单
    def addSingleForm(self, index):

        _translate = QtCore.QCoreApplication.translate
        setattr(self, "code_out" + "@" + str(index),QtWidgets.QTextBrowser(self))
        getattr(self, "code_out" + "@" + str(index)).setGeometry(QtCore.QRect(360, 40 + 90 * index, 100, 90))
        getattr(self, "code_out" + "@" + str(index)).setMinimumSize(QtCore.QSize(self.configFile["code_out_width"], self.configFile["code_out_hight"]))
        getattr(self, "code_out" + "@" + str(index)).setMaximumSize(QtCore.QSize(self.configFile["code_out_width"], self.configFile["code_out_hight"]))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(16)
        getattr(self, "code_out" + "@" + str(index)).setFont(font)
        getattr(self, "code_out" + "@" + str(index)).setObjectName("code_out" + "@" +  str(index))
        getattr(self, "code_out" + "@" + str(index)).setHtml(_translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Adobe Arabic\'; font-size:16pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'SimSun\'; font-size:9pt;\"><br /></p></body></html>"))


        setattr(self, "account_out" + "@" + str(index),QtWidgets.QTextBrowser(self))
        getattr(self, "account_out" + "@" + str(index)).setGeometry(QtCore.QRect(30, 40 + 90 * index, 200, 90))
        getattr(self, "account_out" + "@" + str(index)).setMinimumSize(QtCore.QSize(self.configFile["account_out_width"], self.configFile["account_out_hight"]))
        getattr(self, "account_out" + "@" + str(index)).setMaximumSize(QtCore.QSize(self.configFile["account_out_width"], self.configFile["account_out_hight"]))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(16)
        getattr(self, "account_out" + "@" + str(index)).setFont(font)
        getattr(self, "account_out" + "@" + str(index)).setObjectName("account_out" + "@" + str(index))
        getattr(self, "account_out" + "@" + str(index)).setHtml(_translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Adobe Arabic\'; font-size:16pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'SimSun\'; font-size:9pt;\"><br /></p></body></html>"))


        setattr(self, "copy_button" + "@" + str(index), QtWidgets.QPushButton(self))
        getattr(self, "copy_button" + "@" + str(index)).setGeometry(QtCore.QRect(600, 40 + 90 * index, 70, 60))
        getattr(self, "copy_button" + "@" + str(index)).setMinimumSize(QtCore.QSize(70, 60))
        getattr(self, "copy_button" + "@" + str(index)).setMaximumSize(QtCore.QSize(70, 60))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        getattr(self, "copy_button" + "@" + str(index)).setFont(font)
        getattr(self, "copy_button" + "@" + str(index)).setObjectName("addbutton")
        getattr(self, "copy_button" + "@" + str(index)).setText(_translate("Dialog", "复制"))

        setattr(self, "del_button" + "@" + str(index), QtWidgets.QPushButton(self))
        getattr(self, "del_button" + "@" + str(index)).setGeometry(QtCore.QRect(680, 40 + 90 * index, 70, 60))
        getattr(self, "del_button" + "@" + str(index)).setMinimumSize(QtCore.QSize(70, 60))
        getattr(self, "del_button" + "@" + str(index)).setMaximumSize(QtCore.QSize(70, 60))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        getattr(self, "del_button" + "@" + str(index)).setFont(font)
        getattr(self, "del_button" + "@" + str(index)).setObjectName("addbutton")
        getattr(self, "del_button" + "@" + str(index)).setText(_translate("Dialog", "删除"))

        getattr(self, "code_out" + "@" + str(index)).show()
        getattr(self, "account_out" + "@" + str(index)).show()
        getattr(self, "del_button" + "@" + str(index)).show()
        getattr(self, "copy_button" + "@" + str(index)).show()

        getattr(self, "del_button" + "@" + str(index)).clicked.connect(lambda: self.deleteConfig(index))
        getattr(self, "copy_button" + "@" + str(index)).clicked.connect(lambda: self.copyCode(index))

        tipsButton =  QtWidgets.QPushButton(self)
        tipsButton.setStyleSheet("QPushButton {"
                         "background-image: url(path_to_your_image.png);"
                         "border: none;"
                         "}"
                         "QPushButton:hover {"
                         "background-image: url(path_to_your_hover_image.png);"
                         "}")
        setattr(self, "tips" + "@" + str(1),tipsButton)
        getattr(self, "tips" + "@" + str(1)).setGeometry(QtCore.QRect(300, 300, 150, 60))
        getattr(self, "tips" + "@" + str(1)).setMinimumSize(QtCore.QSize(150, 60))
        getattr(self, "tips" + "@" + str(1)).setMaximumSize(QtCore.QSize(150, 60))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(12)
        getattr(self, "tips" + "@" + str(1)).setFont(font)
        getattr(self, "tips" + "@" + str(1)).setObjectName("tips")
        getattr(self, "tips" + "@" + str(1)).setText(_translate("Dialog", "复制成功"))

        getattr(self,"tips" + "@" + str(1)).hide()

    # 删除配置
    def deleteConfig(self, index):
        reply = QMessageBox.question(None, '确认', '您确定要执行此操作吗？',
                                 QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            getattr(self,"code_out" + "@" + str(len(self.configFile["data"]) - 1)).hide()
            getattr(self,"account_out" + "@" + str(len(self.configFile["data"]) - 1)).hide()
            getattr(self,"del_button" + "@" + str(len(self.configFile["data"]) - 1)).hide()
            getattr(self,"copy_button" + "@" + str(len(self.configFile["data"]) - 1)).hide()
            delattr(self,"code_out" + "@" + str(len(self.configFile["data"]) - 1))
            delattr(self,"account_out" + "@" + str(len(self.configFile["data"]) - 1))
            delattr(self,"del_button" + "@" + str(len(self.configFile["data"]) - 1))
            delattr(self,"copy_button" + "@" + str(len(self.configFile["data"]) - 1))
            self.configFile["data"].pop(index)

            # 写入到文件
            with open("data.json", "w") as json_file:
                json.dump(self.configFile, json_file)
            self.refreshContent()

    def decode_qr_code(self, qr_image_path):
        image = Image.open(qr_image_path)
        decoded_objects = decode(image)

        # 假设只有一个解码结果，且我们只关心解码出的数据
        data = decoded_objects[0].data.decode('utf-8')
        print(data)
        # 提取URL
        return data


    # 导入二维码
    def importQrCode(self):
        # 弹出文件选择对话框，并获取选择的文件路径
        try:
            file_path = QFileDialog.getOpenFileName(self, 'Open File', '', 'All Files (*)')
            if file_path[0]:  # 如果用户选择了文件
                # data = self.decode_qr_code("test.jpg")
                account, secret = self.myqrcode.getSecretAndAccount(file_path[0])
                self.secret_input.setText(secret)
                self.account_input.setText(account)
                self.addConfig()
        except Exception as e:
            print(e)
            QMessageBox.information(None, '提示', '导入失败，请检查二维码是否正确！', QMessageBox.Ok)

    # 复制到剪切板
    def copyCode(self, index):
        t = getattr(self, "code_out" + "@" + str(index)).toPlainText()
        clipboard = QApplication.clipboard()
        clipboard.setText(t)
        self.copyMsg(1)
        self.executor.submit(self.hideMsg)


    def hideMsg(self):
        time.sleep(1.5)  # 假设任务需要3秒钟完成
        getattr(self,"tips" + "@" + str(1)).hide()

    def copyMsg(self, t):
        if t == 1 :
            getattr(self,"tips" + "@" + str(1)).show()





if __name__ == "__main__":
    #固定的，PyQt5程序都需要QApplication对象。sys.argv是命令行参数列表，确保程序可以双击运行
    app = QApplication(sys.argv)
    #初始化
    myWin = MyMainForm()
    #将窗口控件显示在屏幕上
    myWin.show()
    #程序运行，sys.exit方法确保程序完整退出。
    sys.exit(app.exec_())
